package com.cskaoyan.javase.oop2._1extend._6initialization._1basic;

/**
 * @description: 案例说明
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 引例:
 * - - 创建一个Person类，有name属性和eat方法
 *   - 创建一个Star类，有stageName属性和sing方法
 *   - Star类要继承Person类
 *   - 创建Star类对象，画出这个过程的内存图
 *
 * 首先进行类加载,类加载是先父后子的,并且永远从最顶层的父类开始类加载,直到子类自身类加载
 *      Java当中任何类都需要进行类加载,包括jdk当中存在的类,区别是类加载器不同
 *      类加载的时机:
 *          1,启动main方法
 *          2,new对象
 *          3,访问静态成员
 *          4,触发子类类加载会先去类加载父类
 * 类加载结束后,开始创建对象,并且堆上只会创建一个子类对象,
 * 并不会创建父类对象,而是在子类对象当中开辟一片独立的空间,用来存放那些属于父类的成员变量
 * 对象结构存在堆上,其中的成员变量就会具有默认值,这个先后顺序不用考虑的
 * 而子类成员变量的赋值依赖于父类成员,所以父类成员应该先完成赋值,这里也是"先父后子"
 *
 * 先父后子进行类加载是通过JVM的设置去完成的,那么成员变量的"先父后子"是怎么完成的呢?
 * 我们通过构造代码块的输出是"先父后子"的,说明构造器执行了,并且也是"先父后子"
 *
 * 我并没有在代码中任何位置去调用父类构造器,为什么父类构造器会被执行?
 *
 * 子类对象的隐式初始化:
 *      在java类的任何一个构造器中,如果第一行没有this(参数)去调用其他构造器,就会在第一行隐式调用super()表示调用父类的无参构造方法
 *      这种创建子类对象的方法称之为"子类对象的隐式初始化"
 *      它是为了保证父类的构造器先于子类构造器执行,这样父类当中的其它赋值方式都会先于子类执行
 *
 * 子类对象的显式初始化:
 *      隐式初始化无法给父类成员变量赋值,所以需要显式初始化给父类成员变量赋值
 *      语法:
 *          直接在子类构造器的第一行,写super(参数)表示调用父类的某个构造器
 * 这样子类对象创建时,就可以完成父类成员变量的赋值
 *
 * 注意事项:
 *      1,任何构造器的第一行只要没有显式的直接用super(参数)或者this(参数)去调用别的构造器,都会隐含super()
 *      2,创建子类对象过程中,虽然调用了父类构造器,但是不存在父类对象
 *      3,this(参数)调用构造器必须在构造方法的第一行,super(参数)也必须在第一行
 *          所以很明显它们两个关键字是无法共存的
 *
 */
public class Demo {
    public static void main(String[] args) {
        //Star s = new Star();
        Star s = new Star("张三", "法外狂徒");
        System.out.println(s.name); //张三
        System.out.println(s.stageName); //法外狂徒
    }
}
class Person{
   /* static {
        System.out.println("Person类类加载了!");
    }*/
    String name = "长风";
    //构造代码块
    {
        System.out.println("父类Person的构造代码块");
    }
    public void eat(){
        System.out.println("吃饭");
    }
    //构造器
    public Person() {
        //super()
        System.out.println("父类无参构造");
    }

    public Person(String name) {
        this.name = name;
    }
}
class Star extends Person{
    /*static {
        System.out.println("Star类类加载了!");
    }*/
    {
        System.out.println("子类Star的构造代码块");
    }
    //子类成员变量的赋值依赖于父类成员,所以父类成员应该先完成赋值
    String stageName = name + "的弟弟"; //艺名
    public void sing(){
        System.out.println("唱歌");
    }

    //构造器
    public Star() {
        //隐含super()
        System.out.println("子类无参构造");
    }

    public Star(String stageName) {
        this.stageName = stageName;
    }

    public Star(String name,String stageName){
        super(name);
        this.stageName = stageName;
    }
}